#include <cstdlib>
#include <vector>
#include "glesProgram.h"

static void getShaderMsg(GLuint shader, std::string& errMsg)
{
    GLint infoLen = 0;
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
    if (infoLen > 1)
    {
        std::vector<char> tempBufer(infoLen + 1, 0);
        glGetShaderInfoLog(shader, infoLen, NULL, tempBufer.data());
        errMsg = tempBufer.data();
    }
    else
    {
        errMsg = "unknown shader compile error";
    }
}

GLuint gles_load_shader(GLenum shaderType, const char* shaderStr, std::string& errMsg)
{
    GLuint shader;
    GLint compiled;

    // Create the shader object
    shader = glCreateShader(shaderType);

    if (shader == 0)
    {
        errMsg = "glCreateShader failed";
        return 0;
    }

    // Load the shader source
    glShaderSource(shader, 1, &shaderStr, NULL);

    // Compile the shader
    glCompileShader(shader);

    // Check the compile status
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);

    if (!compiled)
    {
        getShaderMsg(shader, errMsg);
        glDeleteShader(shader);
        return 0;
    }

    return shader;
}
GLuint gles_load_program(const char* vShader, const char* fShader, std::string errMsg)
{
    GLuint vertexShader;
    GLuint fragmentShader;
    GLuint programObject;
    GLint linked;

    // Load the vertex/fragment shaders
    vertexShader = gles_load_shader(GL_VERTEX_SHADER, vShader,errMsg);

    if (vertexShader == 0)
    {
        return 0;
    }

    fragmentShader = gles_load_shader(GL_FRAGMENT_SHADER, fShader,errMsg);

    if (fragmentShader == 0)
    {
        glDeleteShader(vertexShader);
        return 0;
    }

    // Create the program object
    programObject = glCreateProgram();

    if (programObject == 0)
    {
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);
        errMsg = "glCreateProgram failed";
        return 0;
    }

    glAttachShader(programObject, vertexShader);
    glAttachShader(programObject, fragmentShader);

    // Link the program
    glLinkProgram(programObject);

    // Check the link status
    glGetProgramiv(programObject, GL_LINK_STATUS, &linked);

    if (!linked)
    {
        GLint infoLen = 0;
        glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &infoLen);
        if (infoLen > 1)
        {
            std::vector<char> tempBufer(infoLen + 1, 0);
            glGetProgramInfoLog(programObject, infoLen, NULL, tempBufer.data());
            errMsg = tempBufer.data();
        }
        else
        {
            errMsg = "unknown program link error";
        }
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);

        glDeleteProgram(programObject);
        return 0;
    }

    // Free up no longer needed shader resources
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    return programObject;
}